package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.IdAndNumDTO;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.utils.*;
import com.tianji.learning.domain.dto.LearningPlanDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.domain.vo.LearningLessonVO;
import com.tianji.learning.domain.vo.LearningPlanPageVO;
import com.tianji.learning.domain.vo.LearningPlanVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 学生课程表 服务实现类
 * </p>
 *
 * @author zhongweiwei
 * @since 2023-05-24
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {
    private final CourseClient courseClient;
    private final CatalogueClient catalogueClient;
    private final LearningRecordMapper recordMapper;

    /**
     * 支付成功后加入课表
     *
     * @param userId
     * @param courseIds
     */
    @Override
    @Transactional
    public void addlesson(Long userId, List<Long> courseIds) {
        //1-  查询用户为该用户指定的课程列表信息
        List<CourseSimpleInfoDTO> simpleInfoList = courseClient.getSimpleInfoList(courseIds);
        //-2判断用户课程信息是否符合
        if (CollUtils.isEmpty(simpleInfoList)) {
            log.debug("查询用户为该用户指定的课程列表信息失败:{}", simpleInfoList);
            return;
        }
        //3- 遍历获取用户对应的课程信息
        List<LearningLesson> list = new ArrayList<>(simpleInfoList.size());
        for (CourseSimpleInfoDTO simpleInfoDTO : simpleInfoList) {
            LearningLesson learningLesson = new LearningLesson();
            Integer validDuration = simpleInfoDTO.getValidDuration();
            if (validDuration != null && validDuration > 0) {
                LocalDateTime now = LocalDateTime.now();
                learningLesson.setCreateTime(now);
                learningLesson.setExpireTime(now.plusMonths(validDuration));
            }
            learningLesson.setUserId(userId);
            learningLesson.setCourseId(simpleInfoDTO.getId());
            list.add(learningLesson);

        }
        // 4- 插入数据库记录
        this.saveBatch(list);
    }

    /**
     * 分页查询我的课表
     *
     * @param query
     * @return
     */
    @Override
    public PageDTO<LearningLessonVO> queryMyLessons(PageQuery query) {
        //1-获取当前用户id
        Long userID = UserContext.getUser();
        //构建分页查询条件
        Page<LearningLesson> page = lambdaQuery()
                .eq(ObjectUtils.isNotEmpty(userID), LearningLesson::getUserId, userID)
                .page(query.toMpPage("latest_Learn_time", false));

        List<LearningLesson> records = page.getRecords();
        if (CollUtils.isEmpty(records)) {
            return PageDTO.empty(page);
        }

        Map<Long, CourseSimpleInfoDTO> courseMap = queryCourseSimpleInfoList(records);
        ArrayList<LearningLessonVO> list = new ArrayList<>(records.size());
        for (LearningLesson record : records) {
            LearningLessonVO lessonVO = BeanUtils.copyProperties(record, LearningLessonVO.class);
            //获取课程信息，填充到lessonVO
            CourseSimpleInfoDTO infoDTO = courseMap.get(record.getCourseId());
            lessonVO.setCourseName(infoDTO.getName());
            lessonVO.setCourseCoverUrl(infoDTO.getCoverUrl());
            lessonVO.setSections(infoDTO.getSectionNum());
            list.add(lessonVO);
        }
        return PageDTO.of(page, list);


    }

    /**
     * 查询我正在学习的课程
     *
     * @return
     */
    @Override
    public LearningLessonVO queryMyCurrentLesson() {
        //1-获取用户id
        Long userId = UserContext.getUser();
        if (userId == null) {
            return null;
        }
        // 2.查询正在学习的课程
        LearningLesson lesson = lambdaQuery().
                eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getStatus, LessonStatus.LEARNING.getValue())
                .orderByDesc(LearningLesson::getLatestLearnTime)
                .last("limit 1")
                .one();
        if (BeanUtils.isEmpty(lesson)) {
            return null;
        }
        // 3.拷贝PO基础属性到VO
        LearningLessonVO lessonVO = BeanUtils.copyBean(lesson, LearningLessonVO.class);
        // 4.查询课程信息
        CourseFullInfoDTO courseInfo = courseClient.getCourseInfoById(lessonVO.getCourseId(), false, false);
        if (null == courseInfo) {
            return null;
        }
        lessonVO.setSections(courseInfo.getSectionNum());
        lessonVO.setCourseName(courseInfo.getName());
        lessonVO.setCourseCoverUrl(courseInfo.getCoverUrl());
        // 5.统计课表中的课程数量
        Integer count = lambdaQuery().eq(LearningLesson::getUserId, userId)
                .count();
        lessonVO.setCourseAmount(count);
        // 6.查询小节信息
        List<CataSimpleInfoDTO> infoDTOS =
                catalogueClient.batchQueryCatalogue(CollUtils.singletonList(lesson.getLatestSectionId()));
        if (!CollUtils.isEmpty(infoDTOS)) {
            CataSimpleInfoDTO infoDTO = infoDTOS.get(0);
            lessonVO.setLatestSectionIndex(infoDTO.getCIndex());
            lessonVO.setLatestSectionName(infoDTO.getName());
        }

        return lessonVO;
    }

    /**
     * 查询指定课程的信息
     *
     * @param courseId
     * @return
     */
    @Override
    public LearningLessonVO queryLessonByCourseId(Long courseId) {
        //1-获取用户id
        Long userId = UserContext.getUser();
        if (userId == null) {
            return null;
        }
        LearningLesson lesson = getOne(buildUserIdAndCourseIdWrapper(userId, courseId));
        if (null == lesson) {
            return null;
        }
        LearningLessonVO lessonVO = BeanUtils.copyBean(lesson, LearningLessonVO.class);
        return lessonVO;
    }

    /**
     * 删除指定的课程
     *
     * @param userId
     * @param courseId
     */
    @Override
    public void deleteCourseFromLesson(Long userId, Long courseId) {
        if (userId == null) {
            userId = UserContext.getUser();
        }
        remove(buildUserIdAndCourseIdWrapper(userId, courseId));


    }

    /**
     * 校验当前课程是否报名
     *
     * @param courseId
     * @return
     */
    @Override
    public Long isLessonValid(Long courseId) {
        //1-获取用户id
        Long userId = UserContext.getUser();
        if (userId == null) {
            return null;
        }
        LearningLesson lesson = getOne(buildUserIdAndCourseIdWrapper(userId, courseId));
        if (BeanUtils.isEmpty(lesson)) {
            return null;
        }

        return lesson.getId();
    }

    /**
     * 统计课程学习人数
     *
     * @param courseId
     * @return
     */
    @Override
    public Integer countLearningLessonByCourse(Long courseId) {
        return lambdaQuery().eq(LearningLesson::getCourseId, courseId)
                .in(LearningLesson::getStatus,
                        LessonStatus.LEARNING.getValue(),
                        LessonStatus.FINISHED.getValue(),
                        LessonStatus.NOT_BEGIN.getValue())
                .count();

    }

    /**
     * 创建学习计划
     *
     * @param plan
     */
    @Override
    public void addLearningPlan(LearningPlanDTO plan) {
        //1-获取用户id
        Long userId = UserContext.getUser();
        //2-根据课程表id和用户id查询当前课程
        LearningLesson lesson = queryLessonByUserIdorCourseid(userId, plan.getCourseId());
        // 3-判断此课程是否存在
        if (BeanUtils.isEmpty(lesson)) {
            throw new BadRequestException("当前课程不存在");
        }
        // 4-更新数据
        LearningLesson learningLes = new LearningLesson();
        Integer freq = plan.getFreq();
        learningLes.setId(lesson.getId());
        learningLes.setWeekFreq(freq);
        if (lesson.getPlanStatus() == PlanStatus.NO_PLAN) {
            lesson.setPlanStatus(PlanStatus.PLAN_RUNNING);
        }


    }

    /**
     * 根据用户id和coursedid查询课程
     *
     * @param userId
     * @param courseId
     */
    @Override
    public LearningLesson queryLessonByUserIdorCourseid(Long userId, Long courseId) {
        return getOne(buildUserIdAndCourseIdWrapper(userId, courseId));
    }

    /**
     * 查询学习计划
     *
     * @param query
     * @return
     */
    @Override
    public LearningPlanPageVO queryLearningPlan(PageQuery query) {

        // 1.获取当前登录用户
        Long userId = UserContext.getUser();
        // 2.获取本周起始时间
        LocalDate now = LocalDate.now();
        LearningPlanPageVO result = new LearningPlanPageVO();
        LocalDateTime weekBeginTime = DateUtils.getWeekBeginTime(now);
        LocalDateTime weekEndTime = DateUtils.getWeekEndTime(now);
        //查询本周已经学习的小节的总数量
        Integer count = recordMapper.selectCount(new LambdaQueryWrapper<LearningRecord>()
                .eq(LearningRecord::getUserId, userId)
                .eq(LearningRecord::getFinished, true)
                .gt(LearningRecord::getFinishTime, weekBeginTime)
                .lt(LearningRecord::getFinishTime, weekEndTime));
        result.setWeekFinished(count);
         //查询本周计划学习的小节的总数量
        Integer totalPlan=  getBaseMapper().queryTotalPlan(userId);
result.setWeekTotalPlan(totalPlan);

        // 4.1.分页查询课表信息以及学习计划信息
        Page<LearningLesson> p = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                .in(LearningLesson::getStatus, LessonStatus.NOT_BEGIN, LessonStatus.LEARNING)
                .page(query.toMpPage("latest_learn_time", false));
        List<LearningLesson> records = p.getRecords();
        if (CollUtils.isEmpty(records)) {
            return result.emptyPage(p);
        }
        // 4.2.查询课表对应的课程信息
        Map<Long, CourseSimpleInfoDTO> cMap = queryCourseSimpleInfoList(records);
        // 4.3.统计每一个课程本周已学习小节数量
        List<IdAndNumDTO> list = recordMapper.countLearnedSections(userId,weekBeginTime , weekEndTime);
        Map<Long, Integer> countMap = IdAndNumDTO.toMap(list);
        // 4.4.组装数据VO
        List<LearningPlanVO> voList = new ArrayList<>(records.size());
        for (LearningLesson r : records) {
            // 4.4.1.拷贝基础属性到vo
            LearningPlanVO vo = BeanUtils.copyBean(r, LearningPlanVO.class);
            // 4.4.2.填充课程详细信息
            CourseSimpleInfoDTO cInfo = cMap.get(r.getCourseId());
            if (cInfo != null) {
                vo.setCourseName(cInfo.getName());
                vo.setSections(cInfo.getSectionNum());
            }
            // 4.4.3.每个课程的本周已学习小节数量
            vo.setWeekLearnedSections(countMap.getOrDefault(r.getId(), 0));
            voList.add(vo);
        }
        return result.pageInfo(p.getTotal(), p.getPages(), voList);
    }

    /**
     * 根据用户id和coursedid查询课程
     *
     * @param userId
     * @param courseId
     */


    private Wrapper<LearningLesson> buildUserIdAndCourseIdWrapper(Long userId, Long courseId) {
        LambdaQueryWrapper<LearningLesson> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(LearningLesson::getUserId, userId);
        wrapper.eq(LearningLesson::getCourseId, courseId);
        return wrapper;
    }


    private Map<Long, CourseSimpleInfoDTO> queryCourseSimpleInfoList(List<LearningLesson> records) {
        // 3.1.获取课程id
        Set<Long> cIds = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toSet());
        // 3.2.查询课程信息
        List<CourseSimpleInfoDTO> cInfoList = courseClient.getSimpleInfoList(cIds);
        if (CollUtils.isEmpty(cInfoList)) {
            // 课程不存在，无法添加
            throw new BadRequestException("课程信息不存在！");
        }
        // 3.3.把课程集合处理成Map，key是courseId，值是course本身
        Map<Long, CourseSimpleInfoDTO> cMap = cInfoList.stream()
                .collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
        return cMap;
    }
}
